/**
 * let const 都有暂时性死区
 * 相对于var 无变量提升、有块级作用域
 * 不能重复声明
 */

/*
if (true) {
  name = 'zhangsan'
  console.log(name) //ReferenceError: Cannot access 'name' before initialization

  let name
  console.log(name)
}*/

/**
 * 块级作用域
 */
var msg = 'hello,world'

for (var i = 0; i < msg.length; i++) {
  console.log(msg[i])
}
console.log(i)  //11
// 变量 只用来控制循环，但是循环结束后，它并没有消失，而是泄露成了全局变量。
// 内层作用域可以定义外层作用域同名变量
function fn() {
  let a = 1
  if (true) {
    let a = 3
    console.log(a) //3
  }
  console.log(a)  //1
}

// fn()

// 在let之前使用立即执行函数来创建块级作用域
(function () {
  var i = 'inner'
})()
// 现在使用let
{
  let i = 'output'
}

/**
 * 函数声明类似于 var ，即会提升到全局作用域或函数作用域的头部。
 */

function out() {
  console.log('out')
}

(function () {
  if (false) {
    function out() {
      console.log('inside')
    }
  }
})()
out()  //out

{
  let s = 'secret'
  let sFn = function () {
    console.log(s)
  }
  sFn() //secret

}

/**
 * const 旦声明常量，就必须立即初始化
 * const 实际上保证的并不是变量的值不得改动，而是变量指向的那个内存地址不得改动。
 * 对于简单类型的数据（数值、字符串、布尔值〉而言，值就保存在变量指向的内存地址中，因
 * 此等同于常量。但对于复合类型的数据（主要是对象和数组）而言，变量指向的内存地址保存
 * 的只是 个指针，const 只能保证这个指针是固定的，至于它指向的数据结构是不是可变的，
 * 这完全不能控制
 */

const cs = 'const'

const student = 'zhangsan' // readonly
// student = 'wangwu' //Attempt to assign to const or readonly variable
const person = {
  name: 'ikun',
  age: 22
}
person.age = 18 // 修改属性值
person.title = 'kunkun' // add
console.log(person) // { name: 'ikun', age: 18, title: 'kunkun' }

// person = {} // 报错
const arr = [1, 2, 3, 4]
arr[0] = 11
console.log(arr)  //[ 11, 2, 3, 4 ]
// arr = [11, 2, 2]  // 报错readonly

// 使用Object.freeze冻结对象，只能读，不能修改
Object.freeze(arr)
arr[2] = 44

console.log(arr[2]) // 3 没有改变值

/**
 * var 声明的全局变量是顶层对象（window。global）的属性
 * let const 定义的变量逐渐与顶层对象属性隔离
 */
var e = 'hello'
console.log(window.e) // hello

let f = 'javascript'
const g = 'vue'
console.log(window.f, window.g)  //undefined undefined



